package xyz.hubery.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import xyz.hubery.constant.Constants;
import xyz.hubery.domain.DepthItemVo;
import xyz.hubery.domain.Market;
import xyz.hubery.domain.TurnoverOrder;
import xyz.hubery.dto.MarketDto;
import xyz.hubery.dto.TradeDTO;
import xyz.hubery.feign.MarketServiceFeign;
import xyz.hubery.feign.MatchServiceFeign;
import xyz.hubery.mappers.MarketMappers;
import xyz.hubery.mappers.TurnoverOrderMappers;
import xyz.hubery.model.R;
import xyz.hubery.service.MarketService;
import xyz.hubery.service.TurnoverOrderService;
import xyz.hubery.vo.DepthsVo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/markets")
@Api(tags = "市场管理")
public class MarketController implements MarketServiceFeign {

    @Autowired
    private MatchServiceFeign matchServiceFeign;
    @Autowired
    private MarketService marketService;
    @Autowired
    private TurnoverOrderService turnoverOrderService;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;


    @GetMapping
    @ApiOperation("分页查询市场")
    @PreAuthorize("hasAuthority('trade_market_query')")
    public R<Page<Market>> findPage(Page<Market> page, @RequestParam(required = false) Long tradeAreaId, @RequestParam(required = false) Byte status) {
        Page<Market> marketPage = marketService.findPage(page, tradeAreaId, status);
        return R.ok(marketPage);
    }

    @PostMapping("/setStatus")
    @ApiOperation("设置市场状态")
    @PreAuthorize("hasAuthority('trade_market_update')")
    public R<Void> setStatus(@RequestBody Market market) {
        if (market.getId() == null || market.getStatus() == null) {
            return R.fail("参数错误");
        }
        boolean b = marketService.updateById(market);
        return b ? R.ok() : R.fail("设置市场状态失败");
    }

    @PatchMapping
    @ApiOperation("更新市场")
    @PreAuthorize("hasAuthority('trade_market_update')")
    public R<Void> update(@RequestBody @Validated Market market) {
        boolean b = marketService.updateById(market);
        return b ? R.ok() : R.fail("更新市场失败");
    }

    @PostMapping
    @ApiOperation("新增市场")
    @PreAuthorize("hasAuthority('trade_market_create')")
    public R<Void> save(@RequestBody @Validated Market market) {
        boolean b = marketService.save(market);
        return b ? R.ok() : R.fail("新增市场失败");
    }

    @GetMapping("/all")
    @ApiOperation("查询所有交易市场")
    public R<List<Market>> findAll() {
        List<Market> markets = marketService.list();
        return R.ok(markets);
    }

    @GetMapping("/getMarket")
    @Override
    public MarketDto getMarket(@RequestParam Long sellCoinId, @RequestParam Long buyCoinId) {
        Market market = marketService.getOne(new LambdaQueryWrapper<Market>()
                .eq(Market::getSellCoinId, sellCoinId)
                .eq(Market::getBuyCoinId, buyCoinId)
                .eq(Market::getStatus, 1)
        );
        return MarketMappers.INSTANCE.toDto(market);
    }

    @GetMapping("/getMarketBySymbol")
    @Override
    public MarketDto findBySymbol(@RequestParam String symbol) {
        Market market = marketService.getMarketBySymbol(symbol);
        return MarketMappers.INSTANCE.toDto(market);
    }

    /**
     * 获取所有的交易市场
     *
     * @return
     */
    @GetMapping("/getAllMarkets")
    @Override
    public List<MarketDto> findAllMarkets() {
        List<Market> marketList = marketService.list(new LambdaQueryWrapper<Market>().eq(Market::getStatus, 1));
        return MarketMappers.INSTANCE.toDto(marketList);
    }

    /**
     * 获取深度数据
     *
     * @param symbol 交易对
     * @param step   深度类型
     * @return
     */
    @GetMapping("/getDepthData")
    @Override
    public String findDepthData(@RequestParam String symbol, @RequestParam Integer step) {
        R<DepthsVo> depthsVo = findDepthsVoSymbol(symbol, step + "");
        DepthsVo data = depthsVo.getData();
        return JSON.toJSONString(data);
    }


    @GetMapping("/depth/{symbol}/{depth}")
    @ApiOperation("根据交易对和深度查询当前市场的深度数据")
    public R<DepthsVo> findDepthsVoSymbol(@PathVariable String symbol, @PathVariable String depth) {
        Market market = marketService.getMarketBySymbol(symbol);
        DepthsVo depthsVo = new DepthsVo();
        depthsVo.setPrice(market.getOpenPrice());
        depthsVo.setCnyPrice(market.getOpenPrice());

        Map<String, List<DepthItemVo>> symbolDepthMap = matchServiceFeign.querySymbolDepth(symbol);
        depthsVo.setAsks(symbolDepthMap.get("asks"));
        depthsVo.setBids(symbolDepthMap.get("bids"));

        return R.ok(depthsVo);
    }

    @GetMapping("/trades/{symbol}")
    @ApiOperation("查询该市场所有的成交记录")
    public R<List<TurnoverOrder>> getAllMarketTurnoverOrder(@PathVariable("symbol") String symbol) {
        List<TurnoverOrder> orders = turnoverOrderService.getAllMarketTurnoverOrder(symbol);
        return R.ok(orders);
    }

    /**
     * 获取市场下所有的交易记录
     *
     * @param id 市场id
     * @return 成交记录列表
     */
    @GetMapping("/trades")
    @Override
    public List<TradeDTO> getAllTradesById(@RequestParam Long id) {
        List<TurnoverOrder> turnoverOrders = marketService.listTradesById(id);
        return TurnoverOrderMappers.INSTANCE.toDto(turnoverOrders);
    }


    /**
     * K 线的查询
     *
     * @param symbol 交易对
     * @param type   K 线类型
     * @return
     */
    @GetMapping("/kline/{symbol}/{type}")
    public R<List<JSONArray>> queryKLine(@PathVariable("symbol") String symbol, @PathVariable("type") String type) {
        // K 线放在 Redis 里面
        String redisKey = Constants.REDIS_KEY_TRADE_KLINE +
                symbol.toLowerCase() +
                ":" +
                type;

        // 因为该请求发生在第一次获取k线，所以返回历史保存的所有k线数据
        List<String> lines = redisTemplate.opsForList().range(redisKey, 0, Constants.REDIS_MAX_CACHE_KLINE_SIZE - 1);
        assert lines != null;
        List<JSONArray> result = new ArrayList<>(lines.size());
        if (!CollectionUtils.isEmpty(lines)) {
            for (String kline : lines) {
                JSONArray objects = JSON.parseArray(kline);
                result.add(objects);
            }
            return R.ok(result);
        }
        return null;
    }

}
